﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace ZWFrameWork
{
    /// <summary>
    /// 大厅服务器游戏服务器
    /// </summary>
    public class ChatClient:SingletonMonoBehaviour<ChatClient>
    {
        /// <summary>
        /// WebSocket
        /// </summary>
        private BestHTTP.WebSocket.WebSocket _webSocket;
        /// <summary>
        /// 当前客户端名字
        /// </summary>
        public string clientName = "Chat";
        /// <summary>
        /// socket连接成功
        /// </summary>
        private Action socketConnectSuccess;
        /// <summary>
        /// socket连接失败
        /// </summary>
        private Action socketConnectFail;
        /// <summary>
        /// 参数
        /// </summary>
        private int _mainId = 1, _assistantID = 2;
        //socket接受字节数组
        private ByteArrays socketReceiveBuffers;
        //接受队列
        private Queue<byte[]> receiveByteArrayQueue;
        //发送队列
        private Queue<byte[]> sendByteArrayQueue;
        
        public bool mIsOpenHeartCheck = true;
        public float mHeartCheckTime = 23;
        private float mCurHeartTime = 0;
        /// <summary>
        /// 初始化websocket
        /// </summary>
        /// <param name="url"></param>
        public void Init(Action _socketConnectSuccess,Action _socketConnectFail)
        {
            _webSocket = new BestHTTP.WebSocket.WebSocket(new Uri(NetConfig.LOGIN_SERVER_URL));
            _webSocket.OnOpen += OnOpen;
            _webSocket.OnClosed += OnClosed;
            _webSocket.OnError += OnError;
            _webSocket.OnBinary += OnBinary;
            socketConnectSuccess = _socketConnectSuccess;
            socketConnectFail = _socketConnectFail;
            socketReceiveBuffers = new ByteArrays();
            receiveByteArrayQueue = new Queue<byte[]>();
            sendByteArrayQueue = new Queue<byte[]>();
        }

        /// <summary>
        /// 是否已经连接
        /// </summary>
        /// <returns></returns>
        public bool isConnected()
        {
            if (_webSocket == null)
            {
                return false;
            }

            return _webSocket.IsOpen;
        }

        /// <summary>
        /// 处理发送队列
        /// </summary>
        private void OperatorSendQueueHandler()
        {
            if (sendByteArrayQueue.Count > 0)
            {
                while (sendByteArrayQueue.Count > 0)
                {
                    // print("sendByteArrayQueue.Count==============="+sendByteArrayQueue.Count);
                    SendMessage(sendByteArrayQueue.Dequeue());
                }
            }
        }
        
        /// <summary>
        /// 处理接受队列
        /// </summary>
        private void OperatorReceiveQueueHandler()
        {
            ///接受队列里有消息
            if (receiveByteArrayQueue.Count>0)
            {
                // GameUtilty.Info("receiveByteArrayQueue.Count = {0}",receiveByteArrayQueue.Count);
                while (receiveByteArrayQueue.Count > 0)
                {
                    try
                    {
                        HandleServerData(receiveByteArrayQueue.Dequeue());
                    }
                    catch (Exception e)
                    {
                        GameUtilty.Error("异常------{0}",e);
                        throw;
                    }
                }
            }
        }
        
        /// <summary>
        /// 帧事件
        /// </summary>
        private void Update()
        {
            if (_webSocket == null)
                return;
            
            if (!_webSocket.IsOpen)
                return;
        
            //开启心跳检测
            if (mIsOpenHeartCheck)
            {
                //未处理断线
                    if (mCurHeartTime > mHeartCheckTime)
                    {
                        GameUtilty.Error("ChatServer 心跳超时检测断网");
                        CloseSocketAndRelease();
                    }
                    else
                    {
                        mCurHeartTime += Time.deltaTime;
                    }
                }
            
            OperatorSendQueueHandler();
            OperatorReceiveQueueHandler();
        }
        
        /// <summary>
        /// 连接
        /// </summary>
        public void Connect()
        {
            if (_webSocket == null)
            {
                GameUtilty.Error("_websocket为空");
                return;
            }
            
            _webSocket.Open();
        }

        public void ResetHeartTime()
        {
            mCurHeartTime = 0;
        }
        
        /// <summary>
        /// 发送字节
        /// </summary>
        /// <param name="byteData"></param>
        public void SendMessage(byte[] byteData)
        {
            if (_webSocket == null)
            {
                GameUtilty.Error(clientName+"_websocket为空");
                return;
            }

            if (byteData.Length <= 0)
            {
                GameUtilty.Error(clientName+"byteData.Length <= 0");
                return;
            }
        
            _webSocket.Send(byteData);
            ResetHeartTime();
        }

        /// <summary>
        /// 接受字节数据
        /// </summary>
        /// <param name="ws"></param>
        /// <param name="data"></param>
        void OnBinary(BestHTTP.WebSocket.WebSocket ws, byte[] data)
        {
            // GameUtilty.Info("接受数据{0}",data.Length);
            socketReceiveBuffers.Write(data);
            unpackHeader();
        }
        
        /// <summary>
        /// 解开包头
        /// </summary>
        private void unpackHeader()
        {
            while (socketReceiveBuffers.Length >= 4)
            {
                byte[] head = socketReceiveBuffers.GetBytes(4);
                TCP_Info info = NetUtils.bytesToStruct<TCP_Info>(head);
                int bodyLength = info.wPacketSize;
                if (socketReceiveBuffers.Length >= bodyLength)
                {
                    byte[] unpackedbytes = socketReceiveBuffers.Read(bodyLength);
                    byte[] Dedata = new byte[bodyLength];
                    if (Encrypt.decode(unpackedbytes, ref Dedata, (uint)bodyLength))
                    {   
                        // GameUtilty.Info(clientName+"解密成功,将数据加入接受队列");
                        receiveByteArrayQueue.Enqueue(Dedata);
                    }
                    else
                    {
                        GameUtilty.Error(clientName+"解包失败");
                    }
                }
                else
                {
                    GameUtilty.Info(clientName+"继续接受字节");
                    break;
                }
            }
        }

        /// <summary>
        /// 连接成功
        /// </summary>
        /// <param name="ws"></param>
        void OnOpen(BestHTTP.WebSocket.WebSocket ws)
        {
            GameUtilty.Info(clientName+"socket连接成功！！！！！");
            socketConnectSuccess?.Invoke();
        }
        /// <summary>
        /// ConnectAndSend
        /// </summary>
        public void ConnectAndSend(int mainId, int assistantID, byte[] buffer)
        {
            _mainId = mainId;
            _assistantID = assistantID;
            SendTCPValidate();
            SendCMD(_mainId, _assistantID, buffer);
            ResetHeartTime();
        }
        
        /// <summary>
        /// SendCMD
        /// </summary>
        /// <param name="mainId"></param>
        /// <param name="assistantID"></param>
        /// <param name="buffer"></param>
        public void SendCMD(int mainId, int assistantID, byte[] buffer)
        {
            SendData(buffer, mainId, assistantID);
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="mainMsg">消息主体</param>
        /// <param name="mianId">主ID</param>    
        /// <param name="assistantID">辅ID</param>
        /// <returns></returns>
        public void SendData<T>(T t, int mainId, int assistantID) where T : struct
        {
            byte[] mainMsg = NetUtils.StructToBytes(t);
            SendData(mainMsg, mainId, assistantID);
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mainId"></param>
        /// <param name="assistantID"></param>
        public void SendData(byte[] mainMsg, int mainId, int assistantID)
        {
            int length = 8 + mainMsg.Length;
            byte[] buffer = new byte[length];
            TCP_Head head = new TCP_Head();
            head.CommandInfo.wMainCmdID = (ushort)mainId;
            head.CommandInfo.wSubCmdID = (ushort)assistantID;
            GameUtilty.Info(clientName +"发送消息 mainId = {0},assistantID = {1}",mainId,assistantID);
            byte[] btHead = NetUtils.StructToBytes(head);
            for (int i = 0; i < length; i++)
            {
                if (i < 8)
                    buffer[i] = btHead[i];
                else
                    buffer[i] = mainMsg[i - 8];
            }

            byte[] sendData = NetUtils.EncodeByte(buffer);
            if (sendData != null && sendData.Length > 0)
            {
                sendByteArrayQueue.Enqueue(sendData);
            }
        }
        
        /// <summary>
        /// 发送链接验证
        /// </summary>
        public void SendTCPValidate()
        {
            TCP_Validate validate = new TCP_Validate();
            validate.szValidateKey = NetUtils.UTF8ToUTF16(Encrypt.ValidateKey, 128);
            byte[] mainMsg = NetUtils.StructToBytes(validate);
            int length = 8 + mainMsg.Length;
            byte[] buffer = new byte[length];
            TCP_Head head = new TCP_Head();
            head.CommandInfo.wMainCmdID = 0;
            head.CommandInfo.wSubCmdID = 2;
            byte[] btHead = NetUtils.StructToBytes(head);
            for (int index = 0; index < length; index++)
            {
                if (index < 8)
                {
                    buffer[index] = btHead[index];
                }
                else
                {
                    buffer[index] = mainMsg[index - 8];
                }
            }

            AsyncFristSend(buffer);
        }

        /// <summary>
        /// AsyncFristSend
        /// </summary>
        /// <param name="sendBuffer"></param>
        private void AsyncFristSend(byte[] sendBuffer)
        {
            try
            {
                int nOutputLen = sendBuffer.Length;
                byte[] pOutputBuffer = new byte[nOutputLen];
                if (Encrypt.encode(sendBuffer, ref pOutputBuffer, (ushort)nOutputLen, true))
                {
                    if (nOutputLen != pOutputBuffer.Length)
                    {
                        GameUtilty.Error(clientName+"发送数据异常");
                        return;
                    }

                    int sendbytesLength = pOutputBuffer.Length + 2;
                    byte[] sendbytes = new byte[sendbytesLength];

                    for (int index = 0; index < 8; index++)
                    {
                        sendbytes[index] = pOutputBuffer[index];
                    }
                    ///组平台识别属性
                    UInt32 p = (UInt32)ENCODE_PLATFORM.CLIENT_U3D;
                    byte[] platform = BitConverter.GetBytes(p);
                    for (int index = 8; index < 10; index++)
                    {
                        sendbytes[index] = platform[index - 8];
                    }

                    for (int index = 10; index < sendbytesLength; index++)
                    {
                        sendbytes[index] = pOutputBuffer[index - 2];
                    }

                    nOutputLen = nOutputLen + 2;
                    if (nOutputLen != sendbytes.Length)
                        GameUtilty.Error(clientName+"发送数据异常");
                    else
                        sendByteArrayQueue.Enqueue(sendbytes);
                }
            }
            catch (Exception e)
            {
                GameUtilty.Error("AsyncFristSend", e.ToString());
            }
        }

        /// <summary>
        /// websocket关闭
        /// </summary>
        /// <param name="ws"></param>
        /// <param name="code"></param>
        /// <param name="message"></param>
        void OnClosed(BestHTTP.WebSocket.WebSocket ws, UInt16 code, string message)
        {
            GameUtilty.Error("关闭socket", message);
        }
        
        /// <summary>
        /// HandleServerData
        /// </summary>
        /// <param name="msgData"></param>
        private void HandleServerData(byte[] msgData)
        {
            //前面4、5、6、7字节为命令
            byte[] cmd = new byte[4];
            Array.Copy(msgData, 4, cmd, 0, 4);
            TCP_Command command = NetUtils.bytesToStruct<TCP_Command>(cmd);
           
            if (command.wMainCmdID != 0 && command.wSubCmdID != 1) //心跳包
            {
                byte[] mainMsg = NetUtils.GetRidOfFrontBytes(msgData, 8);
                // SingletonInstance<LogonNetMessageCenter>.Instance().NetMessageDispatch(command,mainMsg);
            }
            else
            {
                // GameUtilty.Info(clientName + "心跳");
            }

            ResetHeartTime();
        }

        /// <summary>
        /// websocket报错
        /// </summary>
        /// <param name="ws"></param>
        /// <param name="ex"></param>
        public void OnError(BestHTTP.WebSocket.WebSocket ws, String errInfo)
        {
            socketConnectFail?.Invoke();
            GameUtilty.Error("ERROR-------------------------{0}",errInfo);
            CloseSocketAndRelease();
        }
        
        /// <summary>
        /// Close
        /// </summary>
        public void CloseSocketAndRelease()
        {
            if (_webSocket!=null)
            {
                try
                {
                    _webSocket.Close(1006,"byte");
                }
                catch (Exception e)
                {
                    GameUtilty.Error("e ==== {0}",e.Message);
                }

                _webSocket.OnOpen -= OnOpen;
                _webSocket.OnClosed -= OnClosed;
                _webSocket.OnError -= OnError;
                _webSocket.OnBinary -= OnBinary;
            }
            
            ResetHeartTime();
            receiveByteArrayQueue.Clear();
            sendByteArrayQueue.Clear();
            socketReceiveBuffers.Clear();
            socketConnectSuccess = null;
            socketConnectFail = null;
        }
        
        /// <summary>
        /// 清理数据
        /// </summary>
        public override void ClearData()
        {
            CloseSocketAndRelease();
        }
    }
}